package com.supermarket.manage.business.stocking.controller;

import com.alibaba.fastjson.JSON;
import com.supermarket.manage.common.constant.ExportConstant;
import com.supermarket.manage.common.constant.RedisKeyConstant;
import com.supermarket.manage.common.constant.StockConstant;
import com.supermarket.manage.common.dto.CodeStatus;
import com.supermarket.manage.common.dto.PageBean;
import com.supermarket.manage.common.dto.ResponseResult;
import com.supermarket.manage.common.dto.stock.request.StockingPageParams;
import com.supermarket.manage.common.dto.stock.response.StockProdDto;
import com.supermarket.manage.common.dto.stock.response.StockingDto;
import com.supermarket.manage.common.pojo.MyUser;
import com.supermarket.manage.common.pojo.Stocking;
import com.supermarket.manage.common.utils.BigDecimalUtil;
import com.supermarket.manage.common.utils.POIUtil;
import com.supermarket.manage.common.utils.TimeUtil;
import com.supermarket.manage.common.validation.CheckGroup;
import com.supermarket.manage.provider.api.stocking.StockingService;
import com.supermarket.manage.provider.api.ucenter.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotBlank;
import java.io.IOException;
import java.util.*;

/**
 * @author Faxon
 * @version 1.0
 * @date 2020-03-17 16:03
 **/
@RestController
@RequestMapping("/stocking")
@Api(value = "StockingController", tags = "盘点单管理接口")
public class StockingController {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Reference(version = "1.0.0")
    private UserService userService;

    @Reference(version = "1.0.0")
    private StockingService stockingService;

    @PreAuthorize("hasAnyAuthority('/','/stocking/get')")
    @PostMapping("/getStockingPageList")
    @ApiOperation(value = "条件分页查询盘点单", notes = "必传参数：page，size，buyerId（其他为搜索条件）")
    public ResponseResult<PageBean<Stocking>> getStockingPageList(@Validated({CheckGroup.Page.class})
                                                                  @RequestBody StockingPageParams params) {
        PageBean<Stocking> pageBean = stockingService.getStockingPageList(params);
        if (pageBean == null) {
            return new ResponseResult<>(CodeStatus.FAIL, "查询失败");
        }
        List<MyUser> users = userService.getUserByBuyerId(params.getBuyerId());
        pageBean.getDataList().forEach(i -> {
            users.forEach(u -> {
                if (i.getOperator().equals(u.getId())) {
                    i.setOperatorName(u.getUsername());
                }
            });
        });
        return new ResponseResult<>(CodeStatus.OK, "查询成功", pageBean);
    }

    @PreAuthorize("hasAnyAuthority('/','/stocking/get')")
    @GetMapping("/export")
    @ApiOperation(value = "导出采购入库单", notes = "必传参数：buyerId（搜索条件为页面已输入的搜索条件）")
    public void export(@Validated({CheckGroup.Get.class}) StockingPageParams params, HttpServletResponse response) throws IOException {
        List<Stocking> data = stockingService.getStockingList(params);
        List<MyUser> users = userService.getUserByBuyerId(params.getBuyerId());
        data.forEach(i -> {
            users.forEach(u -> {
                if (i.getOperator().equals(u.getId())) {
                    i.setOperatorName(u.getUsername());
                }
            });
        });
        List<Map<String, Object>> maps = new ArrayList<>();
        data.forEach(stocking -> {
            Map<String, Object> map = new HashMap<>(6);
            map.put("id", stocking.getId());
            map.put("operator", stocking.getOperatorName());
            map.put("totalPrice", stocking.getTotalPrice());
            map.put("remark", stocking.getRemark());
            if (stocking.getStatus().equals(StockConstant.DONE)) {
                map.put("status", "已完成");
            } else {
                map.put("status", "未完成");
            }
            map.put("updated", TimeUtil.formatDate(stocking.getUpdated(), TimeUtil.TIME_FORMAT));
            maps.add(map);
        });
        String fileName = ExportConstant.STOCKING_SHEETNAME + TimeUtil.getNow("yyyyMMdd");
        SXSSFWorkbook export = POIUtil.export(fileName, maps, ExportConstant.STOCKING_HEADERSNAME, ExportConstant.STOCKING_KEYS);

        POIUtil.writeTo(fileName, export, response);
    }

    @PreAuthorize("hasAnyAuthority('/','/stocking/get')")
    @GetMapping("/getById/{id}")
    @ApiOperation(value = "根据id获取盘点单详情", notes = "根据id获取盘点单详情")
    public ResponseResult<StockingDto> getStockingById(@NotBlank(message = "单据id不能为空")
                                                       @PathVariable String id) {
        StockingDto stockingDto = stockingService.getStockingById(id);
        if (stockingDto == null) {
            return new ResponseResult<>(CodeStatus.FAIL, "单据不存在");
        }
        //设置经办人名称
        MyUser user = userService.getUserByUserId(stockingDto.getOperator());
        stockingDto.setOperatorName(user.getUsername());
        //未完成的单据可编辑，将关联商品加入redis
        if (stockingDto.getStatus().equals(StockConstant.NOT_DONE)) {
            String key = RedisKeyConstant.STOCKING + id;
            redisTemplate.delete(key);
            List<StockProdDto> prodList = stockingDto.getStockingProds();
            Map<String, String> map = new HashMap<>(prodList.size());
            prodList.forEach(p -> {
                p.setSubtotal(BigDecimalUtil.formatTwoPoint(p.getSubtotal()));
                map.put(p.getPid(), JSON.toJSONString(p));
            });
            if (map.size() > 0) {
                redisTemplate.opsForHash().putAll(key, map);
            }
        }
        return new ResponseResult<>(CodeStatus.OK, "查询成功", stockingDto);
    }

    @PreAuthorize("hasAnyAuthority('/','/stocking/manage')")
    @GetMapping("/doneById/{id}")
    @ApiOperation(value = "根据id完成盘点单据", notes = "根据id完成盘点单据")
    public ResponseResult<Void> doneStockingById(@NotBlank(message = "单据id不能为空")
                                                 @PathVariable String id) {
        Stocking stocking = new Stocking();
        stocking.setId(id);
        stocking.setStatus(StockConstant.DONE);
        Boolean aBoolean = stockingService.doneStockingById(stocking);
        if (aBoolean) {
            return new ResponseResult<>(CodeStatus.OK, "已成功入库");
        }
        return new ResponseResult<>(CodeStatus.FAIL, "入库失败");
    }

    @PreAuthorize("hasAnyAuthority('/','/stocking/manage')")
    @GetMapping("/deleteById/{id}")
    @ApiOperation(value = "根据id删除入库单据", notes = "根据id删除入库单据")
    public ResponseResult<Void> deleteStockingById(@NotBlank(message = "单据id不能为空")
                                                   @PathVariable String id) {
        Boolean aBoolean = stockingService.deleteStockingById(id);
        if (aBoolean) {
            return new ResponseResult<>(CodeStatus.OK, "删除成功");
        }
        return new ResponseResult<>(CodeStatus.FAIL, "删除失败");
    }

    @PreAuthorize("hasAnyAuthority('/','/stocking/manage')")
    @PostMapping("/save")
    @ApiOperation(value = "保存盘点单据", notes = "必传参数：operator（当前登录用户的id），totalPrice，buyerId。（盘点单id在新增时不传，更新时传）" +
            "商品数组中每个商品的必要参数有pid，pnumber，snumber，subtotal（小计=（盘点数量-商品数量）*商品成本价）")
    public ResponseResult<Void> saveStocking(@Validated
                                             @RequestBody Stocking stocking) {
        stocking.setTotalPrice(BigDecimalUtil.formatTwoPoint(stocking.getTotalPrice()));
        stocking.setStatus(StockConstant.NOT_DONE);
        Boolean aBoolean;
        String redisKey;
        //新增单据
        if (StringUtils.isBlank(stocking.getId())) {
            aBoolean = stockingService.addStocking(stocking);
            redisKey = RedisKeyConstant.STOCKING + stocking.getOperator();
        }
        //编辑单据
        else {
            Stocking newStocking = new Stocking();
            newStocking.setId(stocking.getId());
            newStocking.setTotalPrice(stocking.getTotalPrice());
            newStocking.setRemark(stocking.getRemark());
            newStocking.setUpdated(new Date());
            newStocking.setStockingProds(stocking.getStockingProds());
            aBoolean = stockingService.updateStocking(newStocking);
            redisKey = RedisKeyConstant.STOCKING + stocking.getId();
        }
        if (aBoolean) {
            //清空对应购物车
            redisTemplate.delete(redisKey);
            return new ResponseResult<>(CodeStatus.OK, "保存成功");
        }
        return new ResponseResult<>(CodeStatus.FAIL, "保存失败");
    }

    @PreAuthorize("hasAnyAuthority('/','/stocking/manage')")
    @PostMapping("/done")
    @ApiOperation(value = "完成盘点单据", notes = "必传参数：operator（当前登录用户的id），totalPrice，buyerId。（盘点单id在新增时不传，更新时传）" +
            "商品数组中每个商品的必要参数有pid，pnumber，snumber，subtotal（小计=（盘点数量-商品数量）*商品成本价）")
    public ResponseResult<Void> doneStocking(@Validated
                                             @RequestBody Stocking stocking) {
        stocking.setTotalPrice(BigDecimalUtil.formatTwoPoint(stocking.getTotalPrice()));
        stocking.setStatus(StockConstant.DONE);
        Boolean aBoolean;
        String redisKey;
        //新增单据
        if (StringUtils.isBlank(stocking.getId())) {
            aBoolean = stockingService.addStockingAndUpdateStockingNumber(stocking);
            redisKey = RedisKeyConstant.STOCKING + stocking.getOperator();
        }
        //编辑单据
        else {
            Stocking newStocking = new Stocking();
            newStocking.setId(stocking.getId());
            newStocking.setTotalPrice(stocking.getTotalPrice());
            newStocking.setRemark(stocking.getRemark());
            newStocking.setUpdated(new Date());
            newStocking.setStockingProds(stocking.getStockingProds());
            aBoolean = stockingService.updateStockingAndUpdateStockingNumber(newStocking);
            redisKey = RedisKeyConstant.STOCKING + stocking.getId();
        }
        if (aBoolean) {
            //清空对应购物车
            redisTemplate.delete(redisKey);
            return new ResponseResult<>(CodeStatus.OK, "盘点成功");
        }
        return new ResponseResult<>(CodeStatus.FAIL, "盘点失败");
    }
}
